@file:JvmName("CommonExt")

package com.tchhy.provider

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.util.Base64
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.tchhy.basemodule.common.BaseApplication
import com.tchhy.basemodule.glide.KGlideHelper
import com.tchhy.basemodule.widgets.DefaultTextWatcher
import com.tchhy.provider.rx.BaseException
import com.tchhy.provider.rx.ButtonSingleClickSubScribe
import com.tchhy.provider.rx.RxErrorHandle
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.nio.charset.Charset
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.Lock

fun EditText.getTrimText(): String {
    return text.toString().trim()
}

 fun TextView.getTrimText(): String {
    return text.toString().trim()
}

//一些工具方法
fun View.dp2px(dp: Int): Int {
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(),
        resources.displayMetrics
    ).toInt()
}

fun ViewGroup.dp2px(dp: Int): Int {
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(),
        resources.displayMetrics
    ).toInt()
}


fun Context.startServiceForApi26(service: Intent) =
    (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(service)
    } else {
        startService(service)
    })!!


/**
 * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
 */
fun View.dip2px(context: Context, dpValue: Float): Int {
    val scale = context.resources.displayMetrics.density
    return (dpValue * scale + 0.5f).toInt()
}

fun Context.dip2px(dpValue: Float): Int {
    val scale = resources.displayMetrics.density
    return (dpValue * scale + 0.5f).toInt()
}

fun View.onClick(click: () -> Unit) {
    this.setOnClickListener { click() }
}

/**
 * 单次点击
 */
@SuppressLint("CheckResult")
fun View.singleClick(click: () -> Unit, duration: Long = 800): Disposable = Observable.create(
    ButtonSingleClickSubScribe(
        this
    )
)
    .throttleFirst(duration, TimeUnit.MILLISECONDS)
    .subscribe { click.invoke() }


/**
 * 单次点击
 */
@SuppressLint("CheckResult")
fun View.singleClick(click: () -> Unit): Disposable = singleClick({ click.invoke() }, 1000)


/**
 * 关闭键盘
 */
fun View.hideSoftWindow() {
    val imm: InputMethodManager? =
        context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    imm?.hideSoftInputFromWindow(this.windowToken, 0)
}

fun ImageView.loadImageUrl(url: String, radius: Int) {
    KGlideHelper.loadImageRoundedCorners(context, url, this, radius)
}


/**
 * 通过资源id获取color
 */
@ColorInt
fun Context.getColorByExt(@ColorRes id: Int): Int {
    return resources.getColor(id)
}

/**
 * 解密
 */
fun String.decode(): String {
    return String(
        Base64.decode(
            this.substring(0, this.lastIndex).reversed().toByteArray(),
            Base64.DEFAULT
        )
    )
}

/**
 * 加密
 */
fun String.encode(): String {
    val sb = StringBuffer(
        Base64.encodeToString(
            this.toByteArray(Charset.defaultCharset()),
            Base64.DEFAULT
        )
    )
    return sb.reverse().append(sb[0]).toString()
}

/**
 * 设置TextView 的Tint，特效
 */
fun TextView.setDrawableTint(@ColorRes id: Int) {
    compoundDrawables.forEach {
        if (it != null)
            DrawableCompat.setTintList(it, resources.getColorStateList(id))
    }
}

/**
 * 得到屏幕的高
 */
fun Context.getScreenHeight(): Int {
    val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    return (wm.defaultDisplay.height)
}


inline fun <reified T> getObjOrNull(data: Any?) = data as? T

/**
 *通过EditText判断Button是否可用
 */
fun Button.enable(editText: EditText, method: () -> Boolean) {
    editText.addTextChangedListener(object : DefaultTextWatcher() {
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            this@enable.isEnabled = method()
        }
    })
}


infix fun Int.add(value: Int): Int {
    return this + value
}

/**
 * 获取屏幕的宽度px
 *
 * @param context 上下文
 * @return 屏幕宽px
 */
fun Activity.getScreenWidth(): Int {
    val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    val outMetrics = DisplayMetrics()
    windowManager.defaultDisplay.getMetrics(outMetrics)
    return outMetrics.widthPixels
}

/**
 * 判断权限
 *
 */
fun Context.hasPermission(perms: String) =
    ContextCompat.checkSelfPermission(this, perms) == PackageManager.PERMISSION_GRANTED

inline fun Context.hasPermission(perms: String, has: (Boolean) -> Unit) =
    has.invoke(ContextCompat.checkSelfPermission(this, perms) == PackageManager.PERMISSION_GRANTED)

inline fun String.hasPermission(has: () -> Unit) {
    if (ContextCompat.checkSelfPermission(
            BaseApplication.app,
            this
        ) == PackageManager.PERMISSION_GRANTED
    ) has.invoke()
}

/**
 * 改变背景透明度
 *
 */
fun View.setBackgroundAlpha(color: String, frecy: Float) {
    val alpha = Color.alpha(Color.parseColor(color)) * frecy
    val r = Color.red(Color.parseColor(color))
    val g = Color.green(Color.parseColor(color))
    val b = Color.blue(Color.parseColor(color))
    setBackgroundColor(Color.argb(alpha.toInt(), r, g, b))
}


//Int dip 转 px
fun Int.toPx(): Int = BaseApplication.app.dip2px(this.toFloat())





/**
 * try-catch
 *
 *
 */
typealias CatchBlock = (ex: BaseException) -> Unit

typealias TryBlock = () -> Unit

inline fun tryCatch(tryBlock: TryBlock, noinline catchBlock: CatchBlock? = null) = try {
    tryBlock.invoke()
} catch (ex: Exception) {
    catchBlock?.invoke(RxErrorHandle(ex).error())
    ex.printStackTrace()
}


fun launch(launch: suspend () -> Unit) = GlobalScope.launch { launch.invoke() }

fun async(async: suspend () -> Unit) = GlobalScope.async { async.invoke() }


/**
 * Lock接口
 *
 */
typealias LockBlock = () -> Unit

inline fun Lock.lock(locks: LockBlock) = try {
    lock()
    locks.invoke()
} catch (ex: Exception) {
    ex.printStackTrace()
} finally {
    unlock()
}

